#ifndef _RING_QUEUE_HPP_
#define _RING_QUEUE_HPP_

#include <iostream>
#include <vector> 
#include <pthread.h>
#include "Sem.hpp"

const int g_default_num = 5;

// 多生产多消费的意义:
// 不是把任务或者数据放在交易场所，就是生产和消费了
// 将数据或者任务生产前和拿到之后处理，才是最耗费时间的。
// 生产的本质：私有的任务-> 公共空间中
// 消费的本质：公共空间中的任务-> 私有的

// 信号量本质是一把计数器-> 计数器的意义：可以不用进入临界区，就可以得知资源情况，甚至可以减少临界区内部的判断！
// 申请锁 -> 判断与访问 -> 释放锁 --> 本质是并不清楚临界资源的情况！
// 信号量要提前预设资源的情况，而且在pv变化过程中，可以在外部就能知晓临界资源的情况！

template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        :_ring_queue(default_num),
        _num(default_num),
        c_step(0),
        p_step(0),
        _space_sem(default_num),
        _data_sem(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&plock, nullptr);
    }

    
    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }

    //生产者:空间资源 -- 临界资源是下标
    void push(const T& in)
    {
        //先申请信号量
        _space_sem.p();
        pthread_mutex_lock(&plock);
        //一定是竞争成功的生产者线程 -- 一个
        _ring_queue[p_step++] = in;
        p_step %= _num;
        pthread_mutex_unlock(&plock);
        _data_sem.v();
    }

    //消费者:数据资源 -- 临界资源是下标
    void pop(T* out)
    {
        _data_sem.p();
        pthread_mutex_lock(&clock);
        //一定是竞争成功的消费者线程 -- 一个
        *out = _ring_queue[c_step++];
        c_step %= _num;
        pthread_mutex_unlock(&clock);
        _space_sem.v();
    }

    void debug()
    {
        std::cerr << "size: " << _ring_queue.size() << " num: " << _num << std::endl;
    }
private:
    std::vector<T> _ring_queue;
    int _num;
    int c_step;//消费下标
    int p_step;//生产下标
    Sem _space_sem;
    Sem _data_sem;
    pthread_mutex_t clock;
    pthread_mutex_t plock;
};


#endif